package com.gree.flowable.app.controller;

import com.gree.common.utils.RedisUtil;
import com.gree.flowable.app.pojo.cmd.DeleteFlowableProcessInstanceCmd;
import com.gree.flowable.app.pojo.model.*;
import com.gree.flowable.app.pojo.vo.CommentVO;
import com.gree.flowable.app.pojo.vo.ProcessInstanceQueryVO;
import com.gree.flowable.app.pojo.vo.ProcessInstanceVO;
import com.gree.flowable.app.pojo.vo.ReturnVO;
import com.gree.flowable.app.services.IFlowableCommentService;
import com.gree.flowable.app.services.IFlowableProcessInsService;
import com.gree.flowable.app.tools.constants.FlowConstant;
import com.gree.flowable.app.tools.constants.ReturnCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.runtime.ProcessInstanceQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.util.List;

@RestController

@Api(tags = "流程实例管理API")
@RequestMapping("/rest/instance")
public class IFlowableProcessInsApi extends FlowableBaseApi {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ManagementService managementService;

    @Autowired
    private IFlowableProcessInsService iFlowableProcessInsService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private IFlowableCommentService iFlowableCommentService;

    /**
     *@Title:  流程实例的创建
     */
    @PostMapping("/create")
    @ApiOperation("流程实例的创建")
    @ApiImplicitParam(name = "params", value = "启动流程VO", dataType = "StartProcessInstanceMO")
    public ReturnVO createInstance(@RequestBody StartProcessInstanceMO params) {
        ReturnVO result = null;

        String businessKey = params.getBusinessKey();
        if (StringUtils.isEmpty(businessKey)){
            String processKey = params.getProcessDefinitionKey();
            double hincr = redisUtil.hincr("flowable", processKey, 1);
            int sequ = (int) hincr;
            String id;
            for (id = (new StringBuilder(String.valueOf(sequ))).toString();
                 id.length() < 8; ) {
                id = (new StringBuilder("0")).append(id).toString();
            }
            id = (new StringBuilder(String.valueOf(processKey))).append(id).toString();
            params.setBusinessKey(id);
        }
        int count = iFlowableProcessInsService.countBusinessKey(params.getBusinessKey());
        if (count > 0){
            return new ReturnVO(ReturnCode.FAIL, "创建单号失败，不能新建已存在的单号！");
        }
        try {
            ReturnVO<ProcessInstance> returnStart = iFlowableProcessInsService.startProcessInstanceByKey(params);
            if (returnStart.getCode().equals(ReturnCode.SUCCESS)){
                result = new ReturnVO(ReturnCode.SUCCESS, params.getBusinessKey() + "创建成功", params.getBusinessKey());
            }else{
                result = new ReturnVO(ReturnCode.FAIL, returnStart.getMsg());
            }

        }catch (Exception e){
            result = new ReturnVO(ReturnCode.FAIL, businessKey + "创建失败:" + e.getMessage());
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @Title: 跟踪流程 导出流程实例跟踪图
     */
    @GetMapping(value = "/image/{businessKey}")
    @ApiOperation("跟踪流程 导出流程实例跟踪图")
    @ApiImplicitParam(name = "businessKey", value = "业务主键", dataType = "String")
    @Cacheable(value = FlowConstant.CACHE_PROCESS_IMAGE, key = "'" + FlowConstant.PROCESSINSTANCE_PREFIX + "'+ #businessKey")
    public void image(@PathVariable String businessKey, HttpServletResponse response) {
        try {
            byte[] b = iFlowableProcessInsService.createImage(businessKey);
            response.setHeader("Content-Type", "image/png");
            response.getOutputStream().write(b);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @Title: 流程实例的删除
     */
    @DeleteMapping(value = "/bykey/{businessKey}")
    @ApiOperation("流程实例的删除")
    @ApiImplicitParam(name = "businessKey", value = "业务主键", dataType = "String")
    public ReturnVO deleteProcessInstanceById(@PathVariable String businessKey){
        ReturnVO<String> returnVO = null;
        ProcessInstanceQuery query = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessKey);

        long count = query.count();
        if (count > 0){
            // 运行中的流程实例
            String instanceId = query.singleResult().getId();
            DeleteFlowableProcessInstanceCmd cmd = new DeleteFlowableProcessInstanceCmd(instanceId, "删除流程实例", true);
            managementService.executeCommand(cmd);
        }else {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
            historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
        }
        returnVO = new ReturnVO<>(ReturnCode.SUCCESS, "删除成功");
        return returnVO;
    }

    /**
     * @Title: 激活或者挂起流程实例
     * @param: id-流程实例ID
     *         state-需要改变的状态
     * 查看act_ru_execution表 suspension_state == 1  激活状态
     *                     suspension_state == 2  挂起状态
     */
    @PutMapping("/suspense")
    @ApiOperation("激活或者挂起流程实例")
    @ApiImplicitParam(name = "vo", value = "挂起请求参数实体类", dataType = "QuerySaMO")
    public ReturnVO saProcessInstanceById(@RequestBody QuerySaMO vo) {
        ReturnVO returnVO = null;
        Integer suspensionState = vo.getSuspensionState();
        String instanceId = this.rufindPorcInsByKey(vo.getKey());

        if (suspensionState == 2) {
            runtimeService.suspendProcessInstanceById(instanceId);
            returnVO = new ReturnVO(ReturnCode.SUCCESS,"挂起成功");
        } else {
            runtimeService.activateProcessInstanceById(instanceId);
            returnVO = new ReturnVO(ReturnCode.SUCCESS,"激活成功");
        }
        return returnVO;
    }

    /**
     * @Title: 终止流程实例，这个单有问题，或者领导不想继续审批了，废除该单。直接跳到结束节点
     *
     */
    @PutMapping(value = "/terminate")
    @ApiOperation("终止流程实例")
    @ApiImplicitParam(name = "params", value = "终止流程的VO", dataType = "EndProcessMO")
    public ReturnVO stopProcessInsById(@RequestBody EndProcessMO params){
        ReturnVO returnVO = null;
        boolean flag = this.isSuspended(params.getBusinessKey());
        if (flag){
            returnVO = new ReturnVO(ReturnCode.FAIL,"该流程已被挂起，请联系系统管理员！");
        }else {
            returnVO = iFlowableProcessInsService.stopProcessInstanceByKey(params);
        }
        return returnVO;
    }

    /**
     * @Title: 查询我发起的任务
     */
    @PostMapping(value = "/my-instances")
    @ApiOperation("查询我发起的任务")
    @ApiImplicitParam(name = "params", value = "查询流程信息请求VO", dataType = "ProcessInstanceQueryVO")
    public PagerModel<ProcessInstanceVO> myProcessInstances(@RequestBody ProcessInstanceQueryVO params){
//        ObjectMapper mapper = new ObjectMapper();
//        Query query = mapper.convertValue(params.get("query"), Query.class);
        Query query = params.getQuery();

        PagerModel<ProcessInstanceVO> pm = iFlowableProcessInsService.getMyProcessInstances(params, query);
        return pm;
    }

    /**
     * @Title: 撤回api
     */
    @ApiOperation("撤回流程实例")
    @PutMapping(value = "/revoke")
    @ApiImplicitParam(name = "params", value = "撤回流程VO", dataType = "RevokeProcessMO")
    public ReturnVO revokeProcess(@RequestBody RevokeProcessMO params) {
//        params.setUserCode(this.getLoginUser().getId());
        ReturnVO<String> returnVO = iFlowableProcessInsService.revokeProcess(params);
        return returnVO;
    }

    /**
     * @Title: 通过业务主键获取审批意见
     */
    @ApiOperation("获取历史审批意见")
    @GetMapping("/comments/{businessKey}")
    @ApiImplicitParam(name = "businessKey", value = "业务主键", dataType = "String")
    public ReturnVO commentsByProcessInstanceId(@PathVariable String businessKey) {
        List<CommentVO> datas = iFlowableCommentService.getFlowCommentVosByBusinessKey(businessKey);
        ReturnVO result = new ReturnVO(ReturnCode.SUCCESS, "OK", datas);
        return result;
    }

    @ApiOperation("更新流程变量")
    @PostMapping("/variables")
    public ReturnVO uploadVariable(@RequestBody ExecutionVarMO params){
        try {
            String businessKey = params.getBusinessKey();
            Execution execution = runtimeService.createExecutionQuery().processInstanceBusinessKey(businessKey).singleResult();
            String id = execution.getId();
            runtimeService.setVariables(id, params.getVariables());
            return new ReturnVO(ReturnCode.SUCCESS, "操作成功！");
        }catch (Exception e){
            e.printStackTrace();
            return new ReturnVO(ReturnCode.FAIL, "操作失败：" + e.getMessage());
        }
    }
}
